/*
 * controller.cpp
 *
 *      Author: Jerome RD Soine and Christoph A Brand
 *      Institution: Schwarz goup, Institute for Theoretical Physics, Heidelberg University, Germany
 */

#include "../../../../include/base/cell_models/ACM/ActiveCableModel_FA.h"

ActiveCableModel_FA::ActiveCableModel_FA(string filename, string output_folder,
		double spring_constant, vector<double> parameters,
		vector<Ellipse*> FOCAL_ADHESIONS) :
		ActiveCableModel(filename, output_folder, spring_constant, parameters) {

	vector<ForceTransmission*> ft;
	ft.reserve(FOCAL_ADHESIONS.size());
	vector<double> null_force(2,0);
	for(unsigned int i=0; i<FOCAL_ADHESIONS.size(); i++){
		ft.push_back(new ForceTransmission(null_force, FOCAL_ADHESIONS[i]));
	}
	force_transmissions = ft;

	vector<Vertex*> vertices = * g->getVertices();
	corresponding_ft_pos = vector<unsigned int>(vertices.size(),0);
	for(unsigned int j=0; j<vertices.size();j++){
		if(vertices[j]->isFixed()){
			vector<double> p(2,0);
			Vertex point = *vertices[j];
			p[0] = point.getX();
			p[1] = point.getY();
			double distance = FOCAL_ADHESIONS[0]->get_approximate_distance(p);
			unsigned int ft_index = 0;
			for(unsigned int i=1; i<force_transmissions.size(); i++){
				double comp_distance = FOCAL_ADHESIONS[i]->get_approximate_distance(p);
				if(comp_distance < distance) {
					distance = comp_distance;
					ft_index = i;
				}
			}
			corresponding_ft_pos[j]=ft_index;
		}
	}

	for(unsigned int i=0; i<FOCAL_ADHESIONS.size(); i++){
		vertices_at_fa.push_back(init_vertices_at_fa(i));
	}

	for(unsigned int i=0; i<FOCAL_ADHESIONS.size(); i++){
		sf_numbers_at_fa.push_back(init_stress_fiber_numbers_at_fa(i));
	}

	for(unsigned int i=0; i<FOCAL_ADHESIONS.size(); i++){
		sf_numbers_ending_at_fa.push_back(init_stress_fiber_numbers_ending_at_fa(i));
	}
}

ActiveCableModel_FA::~ActiveCableModel_FA(){
}

ActiveCableModel_FA * ActiveCableModel_FA::clone() const{
	vector<Ellipse*> ellipses;
	ellipses.reserve(force_transmissions.size());
	for(unsigned int i=0; i<force_transmissions.size();i++){
		Ellipse * el = (Ellipse *) force_transmissions[i]->get_shape();
		ellipses.push_back(new Ellipse(el->get_center(), el->get_orientation_angle(), el->get_semi_major_axis(), el->get_semi_minor_axis()));
	}
	return new ActiveCableModel_FA(FILENAME, OUTPUT_FOLDER, SPRING_CONSTANT, parameters, ellipses);
}

void ActiveCableModel_FA::run(){
	vector<double> null_force(2,0);
	for(unsigned int i=0; i<force_transmissions.size(); i++) force_transmissions[i]->set_force(null_force);

	//Minimize and specify force transmissions
	minimize(100000);

	vector<Vertex*> vertices = * g->getVertices();
	for(unsigned int i=0; i<vertices.size();i++){
		if(vertices[i]->isFixed()){
			Vertex force = (min->getTotalGradientOfFixedPoints(*vertices[i]))*(-1);
			ForceTransmission * ft = force_transmissions[corresponding_ft_pos[i]];
			vector<double> f(2,0);
			f[0] = force.getX() + ft->get_force()[0];
			f[1] = force.getY() + ft->get_force()[1];
			ft->set_force(f);
		}
	}
}

vector<ForceTransmission*> ActiveCableModel_FA::getForceTransmissionShapes(){
	return force_transmissions;
}

vector<Vertex*> ActiveCableModel_FA::init_vertices_at_fa(unsigned int fa_index){
	vector<Vertex*> vertices_at_fa;
	vector<Vertex*> all_vertices = * g->getVertices();
	for(unsigned int j=0; j<all_vertices.size();j++){
		if(all_vertices[j]->isFixed() && corresponding_ft_pos[j] == fa_index){
			vertices_at_fa.push_back(all_vertices[j]);
		}
	}
	return vertices_at_fa;
}

vector<int> ActiveCableModel_FA::init_stress_fiber_numbers_at_fa(unsigned int fa_index){
	vector<Vertex*> vertices = vertices_at_fa[fa_index];
	vector<int> fiber_numbers_at_fa;
	for(unsigned int j=0; j<vertices.size();j++){
		vector<int> fiber_numbers_at_this_vertex;
		vector<Edge*> conn_edges = *vertices[j]->getEdgesConnectingVertex();
		for(unsigned int i=0; i<conn_edges.size(); i++){
			int type = (int) round(conn_edges[i]->getValueOfAttribute(FIELD_FIBRETYPE));
			int number = (int) round(conn_edges[i]->getValueOfAttribute(FIELD_FIBRENUMBER));
			if(type!=ActiveCableModel::TYPE_NETWORK){
				fiber_numbers_at_this_vertex.push_back(number);
			}
		}
		for(unsigned int i=0; i<fiber_numbers_at_this_vertex.size(); i++){
			bool already_in = false;
			for(unsigned int k=0; k<fiber_numbers_at_fa.size(); k++){
				if(fiber_numbers_at_fa[k]==fiber_numbers_at_this_vertex[i]) already_in = true;
			}
			if(!already_in) fiber_numbers_at_fa.push_back(fiber_numbers_at_this_vertex[i]);
		}
	}
	return fiber_numbers_at_fa;
}

vector<int> ActiveCableModel_FA::init_stress_fiber_numbers_ending_at_fa(unsigned int fa_index){
	vector<Vertex*> vertices = vertices_at_fa[fa_index];
	vector<int> fiber_numbers_ending_at_fa;
	for(unsigned int j=0; j<vertices.size();j++){
		vector<int> fiber_numbers_ending_at_this_vertex;
		vector<Edge*> conn_edges = *vertices[j]->getEdgesConnectingVertex();
		for(unsigned int i=0; i<conn_edges.size(); i++){
			int type = (int) round(conn_edges[i]->getValueOfAttribute(FIELD_FIBRETYPE));
			int number = (int) round(conn_edges[i]->getValueOfAttribute(FIELD_FIBRENUMBER));
			if(type!=ActiveCableModel::TYPE_NETWORK && vertices[j]->isEndpointOfSF(number)){
				fiber_numbers_ending_at_this_vertex.push_back(number);
			}
		}
		for(unsigned int i=0; i<fiber_numbers_ending_at_this_vertex.size(); i++){
			bool already_in = false;
			for(unsigned int k=0; k<fiber_numbers_ending_at_fa.size(); k++){
				if(fiber_numbers_ending_at_fa[k]==fiber_numbers_ending_at_this_vertex[i]) already_in = true;
			}
			if(!already_in) fiber_numbers_ending_at_fa.push_back(fiber_numbers_ending_at_this_vertex[i]);
		}
	}
	return fiber_numbers_ending_at_fa;
}

int ActiveCableModel_FA::get_n_dorsals_at_fa(unsigned int fa_index){
	vector<int> numbers = sf_numbers_at_fa[fa_index];
	vector<int> types = this->getFiberList();
	int count = 0;
	for(unsigned int i=0; i<numbers.size(); i++){
		if(types[numbers[i]] == TYPE_DORSAL) count++;
	}
	return count;
}

int ActiveCableModel_FA::get_n_ventrals_at_fa(unsigned int fa_index){
	vector<int> numbers = sf_numbers_at_fa[fa_index];
	vector<int> types = this->getFiberList();
	int count = 0;
	for(unsigned int i=0; i<numbers.size(); i++){
		if(types[numbers[i]] == TYPE_VENTRAL) count++;
	}
	return count;
}

int ActiveCableModel_FA::get_n_aeb_at_fa(unsigned int fa_index){
	vector<int> numbers = sf_numbers_at_fa[fa_index];
	vector<int> types = this->getFiberList();
	int count = 0;
	for(unsigned int i=0; i<numbers.size(); i++){
		if(types[numbers[i]] == TYPE_EDGEBUNDLE) count++;
	}
	return count;
}

int ActiveCableModel_FA::get_n_tvas_at_fa(unsigned int fa_index){
	vector<int> numbers = sf_numbers_at_fa[fa_index];
	vector<int> types = this->getFiberList();
	int count = 0;
	for(unsigned int i=0; i<numbers.size(); i++){
		if(types[numbers[i]] == TYPE_TVA) count++;
	}
	return count;
}

int ActiveCableModel_FA::get_n_dorsals_ending_at_fa(unsigned int fa_index){
	vector<int> numbers = sf_numbers_ending_at_fa[fa_index];
	vector<int> types = this->getFiberList();
	int count = 0;
	for(unsigned int i=0; i<numbers.size(); i++){
		if(types[numbers[i]] == TYPE_DORSAL) count++;
	}
	return count;
}

int ActiveCableModel_FA::get_n_ventrals_ending_at_fa(unsigned int fa_index){
	vector<int> numbers = sf_numbers_ending_at_fa[fa_index];
	vector<int> types = this->getFiberList();
	int count = 0;
	for(unsigned int i=0; i<numbers.size(); i++){
		if(types[numbers[i]] == TYPE_VENTRAL) count++;
	}
	return count;
}

int ActiveCableModel_FA::get_n_tvas_ending_at_fa(unsigned int fa_index){
	vector<int> numbers = sf_numbers_ending_at_fa[fa_index];
	vector<int> types = this->getFiberList();
	int count = 0;
	for(unsigned int i=0; i<numbers.size(); i++){
		if(types[numbers[i]] == TYPE_TVA) count++;
	}
	return count;
}

int ActiveCableModel_FA::get_n_aeb_ending_at_fa(unsigned int fa_index){
	vector<int> numbers = sf_numbers_ending_at_fa[fa_index];
	vector<int> types = this->getFiberList();
	int count = 0;
	for(unsigned int i=0; i<numbers.size(); i++){
		if(types[numbers[i]] == TYPE_EDGEBUNDLE) count++;
	}
	return count;
}


vector<int> ActiveCableModel_FA::get_stress_fiber_numbers_at_fa(unsigned int fa_index){
	return sf_numbers_at_fa[fa_index];
}
vector<int> ActiveCableModel_FA::get_stress_fiber_numbers_ending_at_fa(unsigned int fa_index){
	return sf_numbers_ending_at_fa[fa_index];
}
vector<Vertex*> ActiveCableModel_FA::get_vertices_at_fa(unsigned int fa_index) {
	return vertices_at_fa[fa_index];
}

